/*
 * @Date: 2023-03-15 19:48:00
 * @LastEditTime: 2023-03-17 15:34:22
 * @FilePath: /hua-fei-chong-zhi/src/sdk/web3Eth.ts
 * 介绍:
 */
import { SdkRes, sdkSucceed, sdkFail } from ".";
import Web3 from "web3";
import ethAbi from "./abi/ethAbi";

function newWeb3() {
  return new Web3(window.ethereum as any);
}

/**判断是不是 Ethereum平台 */
export function sdkIsEthereum() {
  return Boolean(window.ethereum);
}

/**获取当前钱包地址 */
export function sdkGetAddress() {
  return new Promise<string | undefined>((resolve) => {
    newWeb3()
      .eth.getAccounts()
      .then((res) => {
        console.log("获取当前钱包地址", res);
        resolve(res[0]);
      })
      .catch((err) => {
        console.log("获取当前钱包地址失败", err);
        resolve(undefined);
      });
  });
}

/**连接钱包 */
export function sdkConnect() {
  return new Promise<SdkRes<string>>((resolve) => {
    try {
      console.log("连接钱包");
      if (!window.ethereum)
        return resolve(sdkFail("请切换以太坊钱包环境后重试!"));
      window.ethereum
        .request({
          method: "eth_requestAccounts",
        })
        .then(async (res: string[]) => {
          resolve(sdkSucceed("连接钱包成功", res[0]));
        })
        .catch((err: { [key: string]: any }) => {
          resolve(sdkFail("连接钱包失败", err));
        });
    } catch (error: any) {
      resolve(sdkFail("意料之外" + error.message, error));
    }
  });
}

/**
 * * 获取当前网络版号
 * @returns
 */
export function sdkGetChainId() {
  return new Promise<SdkRes<StrNumber>>((resolve) => {
    try {
      console.log("获取网络版号");
      // window
      //   .ethereum!.request({ method: "eth_chainId" })
      //   .then((chainId: string) => {
      //     resolve(
      //       sdkSucceed(parseInt(Number(chainId).toString(), 10).toString())
      //     );
      //   })
      newWeb3()
        ?.eth.getChainId()
        .then((res) => {
          resolve(sdkSucceed("获取网络版号成功", res));
        })
        .catch((error: any) => {
          resolve(sdkFail("获取网络版号失败", error));
        });
    } catch (error: any) {
      resolve(sdkFail("获取网络版号失败" + error.message, error));
    }
  });
}

/**
 * * 授权
 * @param omit 授权合约地址
 * @param amount 支付金额
 * @param format 精度
 * @param toAddress 授权地址
 * @param fromAddress 付款用户地址
 * @returns
 */
export function sdkApprove(
  omit: string,
  amount: number,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    try {
      const vlaue = parseIntAmount(amount, format, "*");
      fromAddress ??= await sdkGetAddress();
      console.log("授权");
      console.log("amount", amount);
      console.log("format", format);
      console.log("vlaue", vlaue);
      console.log("toAddress", toAddress);
      console.log("fromAddress", fromAddress);
      if (!fromAddress) return resolve(sdkFail("授权,获取当前用户地址失败"));
      const web3 = newWeb3();
      const contract = new web3.eth.Contract(ethAbi as any, omit);
      const encodeABI = contract.methods
        .approve(toAddress, web3.utils.toHex(vlaue))
        .encodeABI()
        .substring(2);
      let tx = {
        from: fromAddress,
        to: omit,
        // gasPrice,
        gas: "210000",
        data: encodeABI,
      };
      window
        .ethereum!.request({
          method: "eth_sendTransaction",
          params: [tx],
          from: fromAddress,
        })
        .then((res: string) => {
          resolve(sdkSucceed("授权成功", res));
        })
        .catch((error: any) => {
          resolve(sdkFail("授权失败", error));
        });
    } catch (error: any) {
      resolve(sdkFail("授权失败" + error.message, error));
    }
  });
}

/**
 * * 发起代币转账
 * @param mint 合约地址
 * @param amount 付款金额
 * @param format 精度
 * @param toAddress 收款地址
 * @param fromAddress 付款地址
 */
export function sdkTransferToken(
  mint: string,
  amount: number,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const value = parseAmount(amount, format, "*");
    fromAddress ??= await sdkGetAddress();
    if (!fromAddress) return resolve(sdkFail("授权,获取当前用户地址失败"));
    console.log("代币转账");
    console.log("amount", amount, "format", format, "value", value);
    console.log("mint", mint);
    console.log("toAddress", toAddress);
    console.log("fromAddress", fromAddress);

    const contract = new (newWeb3().eth.Contract)(ethAbi as any, mint);
    contract.methods
      .transfer(toAddress, value)
      .send({
        from: fromAddress,
        gas: "210000",
      })
      .then((res: any) => {
        console.log("代币转账res", res);
        resolve(sdkSucceed("代币转账", res.transactionHash));
      })
      .catch((error: any) => {
        console.log("代币转账");
        resolve(sdkFail(error.message, error));
      });
  });
}

/**金额精度调整-整数 */
function parseIntAmount(
  balance: number | string | void | null,
  format: number,
  mode: "*" | "/" = "/"
): string {
  if (!balance) return "0";
  const toBN = newWeb3().utils.toBN;
  const formatNumber = toBN(10).pow(toBN(format));
  if (mode == "/") return toBN(balance).div(formatNumber).toString();
  return toBN(balance).mul(formatNumber).toString();
}

/**金额精度调整 */
function parseAmount(
  balance: number | string | void | null,
  format: number,
  mode: "*" | "/" = "/"
): string {
  if (!balance) return "0";
  const cause = Math.pow(10, 8);
  balance = Number(balance) * cause;
  const toBN = newWeb3().utils.toBN;
  const formatNumber = toBN(10).pow(toBN(format));
  if (mode == "/")
    return toBN(balance).div(formatNumber).div(toBN(cause)).toString();
  return toBN(balance).mul(formatNumber).div(toBN(cause)).toString();
}
